﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;
using Brain;
using System.Diagnostics;

namespace Brain.Photon
{
#if !WINDOWS_PHONE
    internal struct PhotonParticleCPU
    {
        public Matrix Transform;
        public Color Color;
    }
#endif
    /// <summary>
    /// The Main CPU Renderer of Photon. Does most(MOST) calculation on the CPU rather than on the GPU. Doesn't work on Windows Phone 7
    /// </summary>
#if !WINDOWS_PHONE
    public class PhotonMainCPURenderer : PhotonRenderer
    {
        /// <summary>
        /// Responsible for help Rendering the Particles as Instanced Planes
        /// </summary>
        public InstancingSystem InstancingSystem;

        /// <summary>
        /// The Graphics Device used
        /// </summary>
        public GraphicsDevice GraphicsDevice;

        /// <summary>
        /// The Depth Stencil State to use while Rendering
        /// </summary>
        public DepthStencilState DepthStencilState;

        /// <summary>
        /// The Effect used to draw the particles
        /// </summary>
        internal Effect Effect;

        /// <summary>
        /// The Rasterizer State used while Rendering
        /// </summary>
        public RasterizerState RasterizerState = RasterizerState.CullNone;

        /// <summary>
        /// 4 Vector4 = a matrix
        /// </summary>
        internal static VertexDeclaration instanceVertexDeclaration = new VertexDeclaration
        (
            new VertexElement(0, VertexElementFormat.Vector4, VertexElementUsage.BlendWeight, 0),
            new VertexElement(16, VertexElementFormat.Vector4, VertexElementUsage.BlendWeight, 1),
            new VertexElement(32, VertexElementFormat.Vector4, VertexElementUsage.BlendWeight, 2),
            new VertexElement(48, VertexElementFormat.Vector4, VertexElementUsage.BlendWeight, 3),
            new VertexElement(64, VertexElementFormat.Color, VertexElementUsage.Color, 0)
        );

#if XBOX
        Byte[] effectBytes = new Byte[1984] {188,240,11,207,0,0,0,16,0,0,0,0,0,0,0,1,254,255,9,1,0,0,2,40,0,0,0,0,0,0,0,3,0,0,0,3,0,0,0,96,0,0,0,108,0,0,0,0,0,0,0,4,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,87,111,114,108,100,0,0,0,0,0,0,6,87,79,82,76,68,0,0,0,0,0,0,3,0,0,0,3,0,0,0,212,0,0,0,224,0,0,0,0,0,0,0,4,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,86,105,101,119,0,0,0,0,0,0,0,5,86,73,69,87,0,0,0,0,0,0,0,3,0,0,0,3,0,0,1,72,0,0,1,88,0,0,0,0,0,0,0,4,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,80,114,111,106,101,99,116,105,111,110,0,0,0,0,0,11,80,82,79,74,69,67,84,73,79,78,0,0,0,0,0,5,0,0,0,4,0,0,1,128,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,8,84,101,120,116,117,114,101,0,0,0,0,12,0,0,0,4,0,0,1,204,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,5,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,110,0,0,0,16,0,0,1,164,0,0,1,160,0,0,0,15,84,101,120,116,117,114,101,83,97,109,112,108,101,114,0,0,0,0,0,3,0,0,0,16,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,15,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,80,97,115,115,49,0,0,0,0,0,0,5,80,105,99,107,0,0,0,0,0,0,0,5,0,0,0,1,0,0,0,4,0,0,0,5,0,0,0,4,0,0,0,32,0,0,0,0,0,0,0,0,0,0,0,120,0,0,0,148,0,0,0,0,0,0,0,0,0,0,0,236,0,0,1,8,0,0,0,0,0,0,0,0,0,0,1,104,0,0,1,124,0,0,0,0,0,0,0,0,0,0,1,140,0,0,1,184,0,0,0,0,0,0,0,0,0,0,2,28,0,0,0,0,0,0,0,1,0,0,2,16,0,0,0,0,0,0,0,2,0,0,0,92,0,0,0,0,0,0,1,228,0,0,1,224,0,0,0,93,0,0,0,0,0,0,1,252,0,0,1,248,0,0,0,1,0,0,0,3,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,0,0,0,1,0,0,0,0,0,0,1,112,16,42,17,0,0,0,0,220,0,0,0,148,0,0,0,0,0,0,0,36,0,0,0,140,0,0,0,180,0,0,0,0,0,0,0,0,0,0,0,100,0,0,0,28,0,0,0,87,255,255,3,0,0,0,0,1,0,0,0,28,0,0,0,0,0,0,0,80,0,0,0,48,0,3,0,0,0,1,0,0,0,0,0,64,0,0,0,0,84,101,120,116,117,114,101,83,97,109,112,108,101,114,0,171,0,4,0,12,0,1,0,1,0,1,0,0,0,0,0,0,112,115,95,51,95,48,0,50,46,48,46,49,49,54,50,54,46,48,0,171,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,20,1,252,0,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,0,84,16,0,2,0,0,0,0,8,0,0,0,0,0,0,24,66,0,1,0,3,0,0,0,33,0,0,48,80,0,0,241,160,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,63,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,16,2,0,0,18,0,196,0,0,0,0,0,48,3,0,0,34,0,0,0,0,0,16,8,0,1,31,31,246,136,0,0,64,0,184,16,2,0,1,0,0,67,194,0,0,255,200,0,0,0,0,177,108,0,121,255,2,0,200,15,128,0,0,0,0,0,225,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,0,0,0,0,0,0,0,0,0,0,3,24,16,42,17,1,0,0,1,80,0,0,1,200,0,0,0,0,0,0,0,36,0,0,0,0,0,0,0,252,0,0,0,0,0,0,0,0,0,0,0,212,0,0,0,28,0,0,0,198,255,254,3,0,0,0,0,3,0,0,0,28,0,0,0,0,0,0,0,191,0,0,0,88,0,2,0,8,0,4,0,0,0,0,0,100,0,0,0,116,0,0,0,180,0,2,0,4,0,4,0,0,0,0,0,100,0,0,0,116,0,0,0,185,0,2,0,0,0,4,0,0,0,0,0,100,0,0,0,116,80,114,111,106,101,99,116,105,111,110,0,171,0,3,0,3,0,4,0,4,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,86,105,101,119,0,87,111,114,108,100,0,118,115,95,51,95,48,0,50,46,48,46,49,49,54,50,54,46,48,0,171,171,0,0,0,0,0,0,1,200,0,17,0,8,0,0,0,0,0,0,0,0,0,0,24,66,0,0,0,1,0,0,0,7,0,0,0,2,0,0,2,144,0,16,0,5,0,0,80,6,0,0,160,7,0,0,16,8,0,1,16,9,0,2,16,10,0,35,16,11,0,0,48,80,0,1,241,160,0,0,16,35,0,0,16,36,245,85,96,5,16,11,18,3,18,0,16,1,0,0,0,0,96,12,194,0,18,0,0,0,0,0,96,18,96,24,18,0,18,0,0,0,0,0,80,30,0,0,18,0,196,0,0,0,0,0,32,35,0,0,34,0,0,0,0,0,5,248,32,0,0,0,6,136,0,0,0,0,5,248,0,0,0,0,14,71,0,0,0,0,5,248,16,0,0,0,6,136,0,0,0,0,5,248,96,0,0,0,14,136,0,0,0,0,5,248,112,0,0,0,14,136,0,0,0,0,5,248,128,0,0,0,14,136,0,0,0,0,5,248,64,0,0,0,14,136,0,0,0,0,200,15,0,3,0,108,136,0,161,4,3,0,200,15,0,5,0,177,136,0,161,4,3,0,200,15,0,4,0,198,136,0,161,4,3,0,200,15,0,4,0,198,136,0,171,8,2,4,200,15,0,5,0,177,136,0,171,8,2,5,200,15,0,3,0,108,136,0,171,8,2,3,200,15,0,3,0,108,52,148,171,7,1,3,200,15,0,5,0,177,52,148,171,7,1,5,200,15,0,4,0,198,52,148,171,7,1,4,200,15,0,4,0,198,208,148,171,6,0,4,200,15,0,5,0,177,208,148,171,6,0,5,200,15,0,3,0,108,208,148,171,6,0,3,200,1,0,3,0,170,167,0,239,3,2,0,200,2,0,3,0,170,167,0,239,5,2,0,36,132,3,3,0,170,167,108,239,4,2,128,200,1,0,2,0,62,62,0,111,4,3,0,200,2,0,2,0,62,62,0,111,5,3,0,200,4,0,2,0,62,62,0,111,6,3,0,200,8,0,2,0,62,62,0,111,7,3,0,200,1,128,62,0,167,167,0,175,2,8,0,200,2,128,62,0,167,167,0,175,2,9,0,200,4,128,62,0,167,167,0,175,2,10,0,200,8,128,62,0,167,167,0,175,2,11,0,200,3,128,0,0,197,197,0,226,0,0,0,200,15,128,1,0,0,0,0,226,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,8,84,101,120,116,117,114,101,0 };
#endif
#if WINDOWS
        Byte[] effectBytes = new Byte[1940] {207,11,240,188,16,0,0,0,0,0,0,0,1,0,0,0,1,9,255,254,40,2,0,0,0,0,0,0,3,0,0,0,2,0,0,0,96,0,0,0,108,0,0,0,0,0,0,0,4,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,87,111,114,108,100,0,173,186,6,0,0,0,87,79,82,76,68,0,173,186,3,0,0,0,2,0,0,0,212,0,0,0,224,0,0,0,0,0,0,0,4,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,86,105,101,119,0,240,173,186,5,0,0,0,86,73,69,87,0,240,173,186,3,0,0,0,2,0,0,0,72,1,0,0,88,1,0,0,0,0,0,0,4,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,0,0,0,80,114,111,106,101,99,116,105,111,110,0,186,11,0,0,0,80,82,79,74,69,67,84,73,79,78,0,186,5,0,0,0,4,0,0,0,128,1,0,0,0,0,0,0,0,0,0,0,1,0,0,0,8,0,0,0,84,101,120,116,117,114,101,0,12,0,0,0,4,0,0,0,204,1,0,0,0,0,0,0,0,0,0,0,2,0,0,0,5,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,164,0,0,0,0,1,0,0,164,1,0,0,160,1,0,0,15,0,0,0,84,101,120,116,117,114,101,83,97,109,112,108,101,114,0,186,3,0,0,0,16,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,15,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,80,97,115,115,49,0,173,186,5,0,0,0,80,105,99,107,0,240,173,186,5,0,0,0,1,0,0,0,4,0,0,0,5,0,0,0,4,0,0,0,32,0,0,0,0,0,0,0,0,0,0,0,120,0,0,0,148,0,0,0,0,0,0,0,0,0,0,0,236,0,0,0,8,1,0,0,0,0,0,0,0,0,0,0,104,1,0,0,124,1,0,0,0,0,0,0,0,0,0,0,140,1,0,0,184,1,0,0,0,0,0,0,0,0,0,0,28,2,0,0,0,0,0,0,1,0,0,0,16,2,0,0,0,0,0,0,2,0,0,0,146,0,0,0,0,0,0,0,228,1,0,0,224,1,0,0,147,0,0,0,0,0,0,0,252,1,0,0,248,1,0,0,1,0,0,0,3,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,1,0,0,0,0,0,0,0,12,1,0,0,0,3,255,255,254,255,35,0,67,84,65,66,28,0,0,0,87,0,0,0,0,3,255,255,1,0,0,0,28,0,0,0,0,0,0,32,80,0,0,0,48,0,0,0,3,0,0,0,1,0,0,0,64,0,0,0,0,0,0,0,84,101,120,116,117,114,101,83,97,109,112,108,101,114,0,171,4,0,12,0,1,0,1,0,1,0,0,0,0,0,0,0,112,115,95,51,95,48,0,77,105,99,114,111,115,111,102,116,32,40,82,41,32,72,76,83,76,32,83,104,97,100,101,114,32,67,111,109,112,105,108,101,114,32,57,46,50,54,46,57,53,50,46,50,56,52,52,0,81,0,0,5,0,0,15,160,0,0,0,191,0,0,0,0,0,0,0,0,0,0,0,0,31,0,0,2,5,0,0,128,0,0,3,144,31,0,0,2,10,0,0,128,1,0,15,144,31,0,0,2,0,0,0,144,0,8,15,160,66,0,0,3,0,0,15,128,0,0,228,144,0,8,228,160,2,0,0,3,1,0,15,128,0,0,255,128,0,0,0,160,5,0,0,3,0,8,15,128,0,0,228,128,1,0,228,144,65,0,0,1,1,0,15,128,255,255,0,0,0,0,0,0,0,0,0,0,255,255,255,255,0,0,0,0,0,0,0,0,80,3,0,0,0,3,254,255,254,255,63,0,67,84,65,66,28,0,0,0,198,0,0,0,0,3,254,255,3,0,0,0,28,0,0,0,0,0,0,32,191,0,0,0,88,0,0,0,2,0,8,0,4,0,0,0,100,0,0,0,116,0,0,0,180,0,0,0,2,0,4,0,4,0,0,0,100,0,0,0,116,0,0,0,185,0,0,0,2,0,0,0,4,0,0,0,100,0,0,0,116,0,0,0,80,114,111,106,101,99,116,105,111,110,0,171,3,0,3,0,4,0,4,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,86,105,101,119,0,87,111,114,108,100,0,118,115,95,51,95,48,0,77,105,99,114,111,115,111,102,116,32,40,82,41,32,72,76,83,76,32,83,104,97,100,101,114,32,67,111,109,112,105,108,101,114,32,57,46,50,54,46,57,53,50,46,50,56,52,52,0,171,81,0,0,5,12,0,15,160,0,0,128,63,0,0,0,0,0,0,0,0,0,0,0,0,31,0,0,2,1,0,0,128,0,0,15,144,31,0,0,2,1,0,1,128,1,0,15,144,31,0,0,2,1,0,2,128,2,0,15,144,31,0,0,2,1,0,3,128,3,0,15,144,31,0,0,2,0,0,0,128,4,0,15,144,31,0,0,2,5,0,0,128,5,0,15,144,31,0,0,2,10,0,0,128,6,0,15,144,31,0,0,2,0,0,0,128,0,0,15,224,31,0,0,2,5,0,0,128,1,0,3,224,31,0,0,2,10,0,0,128,2,0,15,224,5,0,0,3,0,0,15,128,1,0,228,160,1,0,0,144,4,0,0,4,0,0,15,128,0,0,228,160,0,0,0,144,0,0,228,128,4,0,0,4,0,0,15,128,2,0,228,160,2,0,0,144,0,0,228,128,4,0,0,4,0,0,15,128,3,0,228,160,3,0,0,144,0,0,228,128,9,0,0,3,0,0,1,128,4,0,228,144,0,0,228,128,5,0,0,3,1,0,15,128,1,0,228,160,1,0,85,144,4,0,0,4,1,0,15,128,0,0,228,160,0,0,85,144,1,0,228,128,4,0,0,4,1,0,15,128,2,0,228,160,2,0,85,144,1,0,228,128,4,0,0,4,1,0,15,128,3,0,228,160,3,0,85,144,1,0,228,128,9,0,0,3,0,0,2,128,4,0,228,144,1,0,228,128,5,0,0,3,1,0,15,128,1,0,228,160,1,0,170,144,4,0,0,4,1,0,15,128,0,0,228,160,0,0,170,144,1,0,228,128,4,0,0,4,1,0,15,128,2,0,228,160,2,0,170,144,1,0,228,128,4,0,0,4,1,0,15,128,3,0,228,160,3,0,170,144,1,0,228,128,9,0,0,3,0,0,4,128,4,0,228,144,1,0,228,128,1,0,0,2,0,0,8,128,12,0,0,160,9,0,0,3,1,0,1,128,0,0,228,128,4,0,228,160,9,0,0,3,1,0,2,128,0,0,228,128,5,0,228,160,9,0,0,3,1,0,4,128,0,0,228,128,6,0,228,160,9,0,0,3,1,0,8,128,0,0,228,128,7,0,228,160,9,0,0,3,0,0,1,224,1,0,228,128,8,0,228,160,9,0,0,3,0,0,2,224,1,0,228,128,9,0,228,160,9,0,0,3,0,0,4,224,1,0,228,128,10,0,228,160,9,0,0,3,0,0,8,224,1,0,228,128,11,0,228,160,1,0,0,2,1,0,3,224,5,0,228,144,1,0,0,2,2,0,15,224,6,0,228,144,255,255,0,0,255,255,255,255,4,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,8,0,0,0,84,101,120,116,117,114,101,0 };
#endif


        /// <summary>
        /// Instantiates a new PhotonMainRenderer
        /// </summary>
        /// <param name="system"></param>
        public PhotonMainCPURenderer(ParticleEmitter emitter)
            : base(emitter)
        {
            Load();
            VertexPositionTexture[] vertices = new VertexPositionTexture[]
            {
                new VertexPositionTexture(
                                new Vector3(1,-1,0),
                                new Vector2(1,1)),
                new VertexPositionTexture(
                                new Vector3(-1,-1,0),
                                new Vector2(0,1)),
                new VertexPositionTexture(
                                new Vector3(-1,1,0),
                                new Vector2(0,0)),
                new VertexPositionTexture(
                                new Vector3(1,1,0),
                                new Vector2(1,0))
            };
            short[] indices = new short[] { 0, 1, 2, 2, 3, 0 };

            VertexBuffer ParticleVertexBuffer = new VertexBuffer(GraphicsDevice,
                VertexPositionTexture.VertexDeclaration, vertices.Length, BufferUsage.None);
            ParticleVertexBuffer.SetData(vertices);

            IndexBuffer ParticleIndexBuffer = new IndexBuffer(GraphicsDevice,
                IndexElementSize.SixteenBits, indices.Length, BufferUsage.None);
            ParticleIndexBuffer.SetData(indices);

            InstancingSystem = new InstancingSystem(ParticleVertexBuffer, ParticleIndexBuffer,
                instanceVertexDeclaration);
        }
        /// <summary>
        /// Instantiates a new PhotonMainRenderer
        /// </summary>
        /// <param name="system"></param>
        /// <param name="meshVertexBuffer">A Vertex Buffer for rendering Particles as Custom Meshes</param>
        /// <param name="meshIndexBuffer">A Index Buffer for the last Vertex Buffer</param>
        public PhotonMainCPURenderer(ParticleEmitter emitter, VertexBuffer meshVertexBuffer, IndexBuffer meshIndexBuffer)
            : base(emitter)
        {
            Load();
            InstancingSystem = new InstancingSystem(meshVertexBuffer, meshIndexBuffer,
                instanceVertexDeclaration);
        }

        private void Load()
        {
            DepthStencilState = DepthStencilState.DepthRead;
            RasterizerState = RasterizerState.CullNone;

            this.IsGPURenderer = false;
            this.CanHandleParticleUpdate = true;
            this.CPU_NeedsTransform = true;

            GraphicsDevice = Engine.Instance.GraphicsDevice;

            Effect = new Effect(GraphicsDevice, effectBytes);
            //Effect = Engine.Instance.ContentManager.Load<Effect>("Engine\\Effects\\fx_Photon");
        }

        /// <inheritdoc />
        public override void Draw()
        {
            GraphicsDevice.DepthStencilState = DepthStencilState;
            GraphicsDevice.RasterizerState = RasterizerState;

            DrawParticleEmmiter(this.ParticleEmitter);

            GraphicsDevice.RasterizerState = RasterizerState.CullCounterClockwise;
        }

        /// <summary>
        /// An array with all the Particles Transforms
        /// </summary>
        internal PhotonParticleCPU[] ParticlesTransforms = new PhotonParticleCPU[0];

        string Time1()
        {
            return "Time: " + Time1V;
        }
        float Time1V;

        /// <summary>
        /// Draws a Particle Emmiter
        /// </summary>
        /// <param name="emitter">The Particle Emmiter you want to draw</param>
        public virtual void DrawParticleEmmiter(ParticleEmitter emitter)
        {
            GraphicsDevice.BlendState = emitter.Properties.BlendState;

            // 1 - Check if our Transforms array is big enough
            if (ParticlesTransforms.Length < emitter.MaxParticles)
            {
                ParticlesTransforms = new PhotonParticleCPU[emitter.MaxParticles];
            }

            // 2 - Check if there is a particle to render
            if (emitter.ActiveParticles == 0)
            {
                return;
            }

            // 3 - Copy Particle's Transforms to our Transforms array
            // and check how much Particles are really there
            // (the Particles array may have some particles null)
            int maxI = 0;
            for (int i = 0; i < emitter.MaxParticles; i++)
            {
                UpdateParticle(i, ref maxI, emitter);
            }
            
            #region New Code
            /*if (emmiter.LastActiveParticle > emmiter.FirstActiveParticle)
            {
                // One loop
                for (int i = emmiter.FirstActiveParticle; i < emmiter.LastActiveParticle; i++)
                {
                    UpdateParticle(i, ref maxI, emmiter);
                }
            }
            else
            {
                // Two loops?
                for (int i = 0; i < emmiter.LastActiveParticle; i++)
                {
                    UpdateParticle(i, ref maxI, emmiter);
                }

                if (emmiter.LastActiveParticle > emmiter.FirstActiveParticle)
                {
                    // When we have many particles the Last Active Particle can get bigger
                    // than the First Active PArticle on the first loop,
                    // what could fuck everything,
                    // so we set the MaxI to 0 (throwing on the trash everything we updates =(  )
                    maxI = 0;
                    for (int i = 0; i < emmiter.MaxParticles; i++)
                    {
                        UpdateParticle(i, ref maxI, emmiter);
                    }
                }
                else
                {
                    for (int i = emmiter.FirstActiveParticle; i < emmiter.MaxParticles; i++)
                    {
                        UpdateParticle(i, ref maxI, emmiter);
                    }
                }
            }*/
            #endregion

            // 4 - Check if our Transforms Vertex Buffer is big enough
            InstancingSystem.ResizeBufferIfNotBig(emitter.MaxParticles);
            
            // 5 - Again, check if we have particles(after updating they may have ended)
            if (emitter.ActiveParticles == 0)
            {
                return;
            }

            // 6 - Set the Transforms to the Instances Vertex Buffer
            InstancingSystem.InstancesVertexBuffer.SetData(ParticlesTransforms, 0, emitter.ActiveParticles, SetDataOptions.Discard);

#if !SILVERLIGHT
            // 7 - Set the Vertex Buffer to the Graphics Device
            GraphicsDevice.SetVertexBuffers(
                new VertexBufferBinding(InstancingSystem.ModelVertexBuffer, 0, 0),
                new VertexBufferBinding(InstancingSystem.InstancesVertexBuffer, 0, 1)
                );
            GraphicsDevice.Indices = InstancingSystem.ModelIndexBuffer;

            Effect.Parameters["View"].SetValue(Engine.Instance.CameraManager.Camera3D.View);
            Effect.Parameters["Projection"].SetValue(Engine.Instance.CameraManager.Camera3D.Projection);
            Effect.Parameters["World"].SetValue(Matrix.Identity);
            Effect.Parameters["Texture"].SetValue(emitter.Properties.Texture);

            // 8 - Render the Particle
            foreach (EffectPass pass in Effect.CurrentTechnique.Passes)
            {
                pass.Apply();

                GraphicsDevice.DrawInstancedPrimitives(PrimitiveType.TriangleList,
                    0, 0, InstancingSystem.ModelVertexBuffer.VertexCount, 0, 2, emitter.ActiveParticles);
            }

            GraphicsDevice.SetVertexBuffer(null);
#endif
        }

        internal void UpdateParticle(int i, ref int maxI, ParticleEmitter emitter)
        {
            Particle p = emitter.Particles[i];
            if (p != null)
            {
                if (ShouldHandleParticleUpdate)
                {
                    if (emitter.UpdateParticle(p, i))
                    {
                        return;
                    }
                }
                
                PhotonParticleCPU ph = new PhotonParticleCPU();
                if (p.Transform != null)
                {
                    ph.Transform = p.Transform.Value;
                }

                Color color = emitter.Properties.StartColor;
                color = ColorUtil.Multiply(color, p.Color);
                if (p.AliveTime > emitter.Properties.StartFadeOutTime)
                {
                    float differenceOfAlive = p.AliveTime - emitter.Properties.MaxTime;
                    float dif = emitter.Properties.DifferenceFromFadeOutToEnd;
                    float amount = (differenceOfAlive / (float)dif) + 1;
                    Color StartColor = color;
                    color = Color.Lerp(StartColor, emitter.Properties.EndColor, amount);
                }
                else if (p.AliveTime < emitter.Properties.TimeToDefaultColor)
                {
                    float differenceOfAlive = emitter.Properties.TimeToDefaultColor - p.AliveTime;
                    float amount = ((emitter.Properties.TimeToDefaultColor - differenceOfAlive) / (float)emitter.Properties.TimeToDefaultColor);
                    Color StartColor = color;
                    color = Color.Lerp(Color.Transparent, StartColor, amount);
                }
                ph.Color = color;

                ParticlesTransforms[maxI] = ph;

                maxI++;


            }
        }

        public override Vector3 GetParticleCurrentPosition(Particle p)
        {
            return p.Position;
        }
        public override float GetParticleTime(Particle p)
        {
            return p.AliveTime;
        }
    }
#endif
}
